/* Copyright (c) 2025 Beijing Semidrive Technology Corporation
 * SPDX-License-Identifier: Apache-2.0
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

/** *****************************************************************************************************
 * \file     Ea_Ops.c                                                                                   *
 * \brief    AUTOSAR 4.3.1 MCAL ea Driver                                                               *
 *                                                                                                      *
 * <table>                                                                                              *
 * <tr><th>Date           <th>Version                                                                   *
 * <tr><td>2024/11/14     <td>1.0.0                               *
 * </table>                                                                                             *
 *******************************************************************************************************/

#ifdef __cplusplus
extern "C" {
#endif

/********************************************************************************************************
 *                                      Include header files                                            *
 *******************************************************************************************************/
#include "cdefs.h"
#include "debug.h"

#include "Mcal_MemLibc.h"
#include "Ea.h"
#include "Ea_Ops.h"
#include "Ea_Crc16.h"
#include "Ea_Cfg.h"
#include "Ea_Fault.h"

#define EA_START_SEC_VAR_NO_INIT_UNSPECIFIED
#include "Ea_MemMap.h"

static struct ea_dev ea_devices[ EA_DEV_NUMBER ];
static struct ea_dev ea_backup_devices[ EA_DEV_NUMBER ];
static struct ea_block_status block_status[ EA_BLOCKS_CFG_NUMBER ];
static struct ea_block_status block_status_backup[ EA_BLOCKS_CFG_NUMBER ];
static uint8 ea_cache_buff[EA_DEV_CACHE_SIZE] __attribute__((aligned(EA_VIRTUAL_PAGE_SIZE)));

#define EA_STOP_SEC_VAR_NO_INIT_UNSPECIFIED
#include "Ea_MemMap.h"

extern Ea_StateType Ea_State;

/********************************************************************************************************
 *                                  Private Function Declarations                                       *
 *******************************************************************************************************/
static Ea_Internal_JobResultType Ea_Internal_JobInt( void );
static Ea_Internal_JobResultType Ea_Internal_JobInt_GetDevInfo( void );
static Ea_Internal_JobResultType Ea_Internal_JobInt_ParesDevInfo( void );
static Ea_Internal_JobResultType Ea_Internal_JobInt_SetDevInfo( void );
static Ea_Internal_JobResultType Ea_Internal_JobInt_SetBlockDataEnd( void );
static Ea_Internal_JobResultType Ea_Internal_JobInt_SetBlockInfoEnd( void );
static Ea_Internal_JobResultType Ea_Internal_JobInt_GetBlockInfo( void );
static Ea_Internal_JobResultType Ea_Internal_JobInt_ParesInfoEndFlag(
    struct ea_dev_info_end *info_end );
static Ea_Internal_JobResultType Ea_Internal_JobInt_DiscardRecordInfo(
    struct ea_record_info *record_info, Eep_AddressType block_info_addr);
static Ea_Internal_JobResultType Ea_Internal_JobInt_ParesRecordInfo(
    struct ea_record_info *record_info, Eep_AddressType block_info_addr);
static Ea_Internal_JobResultType Ea_Internal_JobInt_ParesBlockInfo( void );
static Ea_Internal_JobResultType Ea_Internal_JobInt_BlockInfoLoop( void );
static Ea_Internal_JobResultType Ea_Internal_JobInt_GetDataEndFlag( void );
static Ea_Internal_JobResultType Ea_Internal_JobInt_ParesDataEndFlag( void );
static Ea_Internal_JobResultType Ea_Internal_JobInt_GetBackupBlockInfo( void );
static Ea_Internal_JobResultType Ea_Internal_JobInt_ParesBackupBlockInfo(
    void );
static Ea_Internal_JobResultType Ea_Internal_JobInt_ReadBackupBlockData( void );
static Ea_Internal_JobResultType Ea_Internal_JobInt_SyncBackupBlockData( void );
static Ea_Internal_JobResultType Ea_Internal_JobInt_BackupBlockActive( void );
static Ea_Internal_JobResultType Ea_Internal_JobInt_Done( void );
static Ea_Internal_JobResultType Ea_Internal_Job_Done( void );

#define EA_START_SEC_VAR_INIT_UNSPECIFIED
#include "Ea_MemMap.h"

const Ea_InternalJobFunctionVoidPtr Ea_InterFunc[EA_INTERNAL_JOB_MAX] = {
    Ea_Internal_JobInt,                     /* EA_INTERNAL_JOB_INT */
    Ea_Internal_JobInt_GetDevInfo,          /* EA_INTERNAL_JOB_INT_GET_DEV_INFO */
    Ea_Internal_JobInt_ParesDevInfo,        /* EA_INTERNAL_JOB_INT_PARES_DEV_INFO */
    Ea_Internal_JobInt_SetDevInfo,          /* EA_INTERNAL_JOB_INT_SET_DEV_INFO */
    Ea_Internal_JobInt_SetBlockDataEnd,     /* EA_INTERNAL_JOB_INT_SET_BLOCK_DATA_END */
    Ea_Internal_JobInt_SetBlockInfoEnd,     /* EA_INTERNAL_JOB_INT_SET_BLOCK_INFO_END */
    Ea_Internal_JobInt_GetBlockInfo,        /* EA_INTERNAL_JOB_INT_GET_BLOCK_INFO */
    Ea_Internal_JobInt_ParesBlockInfo,      /* EA_INTERNAL_JOB_INT_PARES_BLOCK_INFO */
    Ea_Internal_JobInt_BlockInfoLoop,       /* EA_INTERNAL_JOB_INT_BLOCK_INFO_LOOP */
    Ea_Internal_JobInt_GetDataEndFlag,      /* EA_INTERNAL_JOB_INT_GET_BLOCK_DATA_END */
    Ea_Internal_JobInt_ParesDataEndFlag,    /* EA_INTERNAL_JOB_INT_PARES_BLOCK_DATA_END */
    Ea_Internal_JobInt_GetBackupBlockInfo,  /* EA_INTERNAL_JOB_INT_GET_BACKUP_BLOCK_INFO */
    Ea_Internal_JobInt_ParesBackupBlockInfo,/* EA_INTERNAL_JOB_INT_PARES_BACKUP_BLOCK_INFO */
    Ea_Internal_JobInt_ReadBackupBlockData, /* EA_INTERNAL_JOB_INT_READ_BACKUP_BLOCK_DATA */
    Ea_Internal_JobInt_SyncBackupBlockData, /* EA_INTERNAL_JOB_INT_SYNC_BACKUP_BLOCK_DATA */
    Ea_Internal_JobInt_BackupBlockActive,   /* EA_INTERNAL_JOB_INT_BACKUP_BLOCK_ACTIVE */
    Ea_Internal_JobInt_Done,                /* EA_INTERNAL_JOB_INT_DONE */
    Ea_Internal_Job_Done,                   /* EA_INTERNAL_JOB_DONE */
};

#define EA_STOP_SEC_VAR_INIT_UNSPECIFIED
#include "Ea_MemMap.h"

/********************************************************************************************************
 *                                  Private Function Declarations                                       *
 *******************************************************************************************************/
static MemIf_JobResultType Ea_JobRead( void );
static MemIf_JobResultType Ea_JobRead_Data( void );
MemIf_JobResultType Ea_JobWrite_BackupBlockInfo( void );
MemIf_JobResultType Ea_JobWrite_SyncBlockInfo( void );
static MemIf_JobResultType Ea_JobWrite( void );
static MemIf_JobResultType Ea_JobWrite_BackupRecordInfo( void );
static MemIf_JobResultType Ea_JobWrite_ReadBackupRecordData( void );
static MemIf_JobResultType Ea_JobWrite_SyncBackupRecordData( void );
static MemIf_JobResultType Ea_JobWrite_BackupRecordActive( void );
static MemIf_JobResultType Ea_JobWrite_MoveBackupRecordInfo( void );
static MemIf_JobResultType Ea_JobWrite_MoveReadBackupRecordData( void );
static MemIf_JobResultType Ea_JobWrite_MoveSyncBackupRecordData( void );
static MemIf_JobResultType Ea_JobWrite_MoveBackupRecordActive( void );
static MemIf_JobResultType Ea_JobWrite_BlockInfoEnd( void );
static MemIf_JobResultType Ea_JobWrite_RecordInfo( void );
static MemIf_JobResultType Ea_JobWrite_BlockDataEnd( void );
static MemIf_JobResultType Ea_JobWrite_RecordData( void );
static MemIf_JobResultType Ea_JobWrite_RecordActive( void );
static MemIf_JobResultType Ea_Job_InvalBlock( void );
static MemIf_JobResultType Ea_Job_InvalBlockInfo( void );
static MemIf_JobResultType Ea_Job_EraseImmediate( void );
static MemIf_JobResultType Ea_Job_Done( void );

#define EA_START_SEC_VAR_INIT_UNSPECIFIED
#include "Ea_MemMap.h"

const Ea_JobFunctionVoidPtr Ea_Module_Func[EA_JOB_MAX] = {
    Ea_JobRead,                             /* EA_JOB_READ */
    Ea_JobRead_Data,                        /* EA_JOB_READ_DATA */
    Ea_JobWrite,                            /* EA_JOB_WRITE */
    Ea_JobWrite_BackupRecordInfo,           /* EA_JOB_WRITE_BACKUP_RECORD_INFO */
    Ea_JobWrite_ReadBackupRecordData,       /* EA_JOB_WRITE_READ_BACKUP_RECORD_DATA */
    Ea_JobWrite_SyncBackupRecordData,       /* EA_JOB_WRITE_SYNC_BACKUP_RECORD_DATA */
    Ea_JobWrite_BackupRecordActive,         /* EA_JOB_WRITE_BACKUP_RECORD_ACTIVE */
    Ea_JobWrite_MoveBackupRecordInfo,       /* EA_JOB_WRITE_MOVE_BACKUP_RECORD_INFO */
    Ea_JobWrite_MoveReadBackupRecordData,   /* EA_JOB_WRITE_MOVE_READ_BACKUP_RECORD_DATA */
    Ea_JobWrite_MoveSyncBackupRecordData,   /* EA_JOB_WRITE_MOVE_SYNC_BACKUP_RECORD_DATA */
    Ea_JobWrite_MoveBackupRecordActive,     /* EA_JOB_WRITE_MOVE_BACKUP_RECORD_ACTIVE */
    Ea_JobWrite_BlockInfoEnd,               /* EA_JOB_WRITE_BLOCK_INFO_END */
    Ea_JobWrite_RecordInfo,                 /* EA_JOB_WRITE_RECORD_INFO */
    Ea_JobWrite_BlockDataEnd,               /* EA_JOB_WRITE_BLOCK_DATA_END */
    Ea_JobWrite_RecordData,                 /* EA_JOB_WRITE_RECORD_DATA */
    Ea_JobWrite_RecordActive,               /* EA_JOB_WRITE_RECORD_ACTIVE */
    Ea_Job_InvalBlock,                      /* EA_JOB_INVAL_BLOCK */
    Ea_Job_InvalBlockInfo,                  /* EA_JOB_INVAL_BLOCK_INFO */
    Ea_Job_EraseImmediate,                  /* EA_JOB_ERASE_IMMEDIATE */
    Ea_Job_Done,                            /* EA_JOB_DONE */
};

#define EA_STOP_SEC_VAR_INIT_UNSPECIFIED
#include "Ea_MemMap.h"

#define EA_START_SEC_CODE
#include "Ea_MemMap.h"

#ifdef EA_DEV_DUMP

inline static int isprint(int c)
{
    return ((c >= 0x20) && (c < 0x7f));
}

inline static void hexdump8_ex(const void *ptr, uint16 len,
                               uint64 disp_addr)
{
    uint32 address = (uint32)ptr;
    uint16 count;
    uint16 i;
    const char *addr_fmt = "0x%08llx: ";

    for (count = 0 ; count < len; count += 16) {
        EA_DEBUG(addr_fmt, count);

        for (i = 0; i < _MIN(len - count, 16); i++) {
            EA_DEBUG("%02x ", *(const uint8 *)(address + i));
        }

        for (; i < 16; i++) {
            EA_DEBUG("   ");
        }

        EA_DEBUG("|");

        for (i = 0; i < _MIN(len - count, 16); i++) {
            char c = ((const char *)address)[i];
            EA_DEBUG("%c", isprint(c) ? c : '.');
        }

        EA_DEBUG("\n");
        address += 16;
    }
}

#endif

static Std_ReturnType Ea_Common_Read(Eep_AddressType addr, uint8 *dst,
                                     Eep_LengthType size)
{
    EA_DEBUG("Ea_Common_Read addr:%llx size:%llx\n", addr, size);

    /* Fault error interface */
    Ea_Read_Exception();

    return Eep_Read(addr, dst, size);
}

static Std_ReturnType Ea_Common_Write(Eep_AddressType addr, const uint8 *src,
                                      Eep_LengthType size)
{
    EA_DEBUG("Ea_Common_Write addr:%llx size:%llx\n", addr, size);

    /* Fault error interface */
    Ea_Write_Exception();

    return Eep_Write(addr, src, size);
}

uint16 Ea_GetBlockIndex(uint16 BlockNumber)
{
    uint16 uRetVal = EA_BLOCK_INDEX_DEF;
    uint16 i = 0;

    /* EA_BLOCKS_CFG_NUMBER Specifies the block configuration of EB */
    for (i = 0; i < EA_BLOCKS_CFG_NUMBER; i++) {
        if (BlockNumber == Ea_BlockConfig[i].blockNumber) {
            uRetVal = i;
            break;
        }
    }

    return uRetVal;
}

static Ea_Internal_JobResultType Ea_Internal_JobInt( void )
{
    Ea_Internal_JobResultType eRetVal = EA_INTERNAL_JOB_FAILED;
    struct ea_dev *pea_dev = NULL_PTR;
    Ea_StateType *pEa_State = &Ea_State;
    uint16 i = 0;

    /* Initialize the local block state */
    Mcal_MemSet(block_status, 0, sizeof(struct ea_block_status) *
                EA_BLOCKS_CFG_NUMBER);

    for (i = 0; i < EA_BLOCKS_CFG_NUMBER; i++) {
        block_status[i].block_number = Ea_BlockConfig[i].blockNumber;
        block_status[i].block_size = Ea_BlockConfig[i].blockSize;
        block_status[i].dev_index = Ea_BlockConfig[i].devIndex;
        block_status[i].block_status = EA_RECORD_UNSET;
    }

    /* Initialize the Ea device Eep-related configurations */
    /*PRQA S 2877 2*/
    for (i = 0; i < EA_DEV_NUMBER; i++) {
        pea_dev = &ea_devices[i];
        Mcal_MemSet(pea_dev, 0x0, sizeof(struct ea_dev));

        pea_dev->dev_index = i;
        pea_dev->dev_addr = Ea_DeviceConfig[i].Eep_startAddr;
        pea_dev->dev_size = Ea_DeviceConfig[i].Eep_length;
        pea_dev->major_version = EA_AR_MAJOR_VERSION;
        pea_dev->minor_version = EA_AR_MINOR_VERSION;
        pea_dev->patch_version = EA_AR_PATCH_VERSION;
    }

    /*
     * Initialize operations from the first ea device
     * Ea_uJobIntDevIt indexes the device
     */
    pEa_State->Ea_uJobIntDevIt = 0;
    eRetVal = Ea_Internal_JobInt_GetDevInfo();

    return eRetVal;
}

static Ea_Internal_JobResultType Ea_Internal_JobInt_GetDevInfo( void )
{
    Std_ReturnType eStdRetVal = (Std_ReturnType)E_OK;
    Ea_Internal_JobResultType eRetVal = EA_INTERNAL_JOB_FAILED;
    Ea_StateType *pEa_State = &Ea_State;
    struct ea_dev *pea_dev = &ea_devices[pEa_State->Ea_uJobIntDevIt];
    struct ea_dev_info *dev_info = (struct ea_dev_info *)(unsigned long int)ea_cache_buff;

    /* Get device information from the starting address of the device */
    Mcal_MemSet(dev_info, 0, sizeof(struct ea_dev_info));
    eStdRetVal = Ea_Common_Read(pea_dev->dev_addr, (uint8 *)dev_info,
                                sizeof(struct ea_dev_info));

    if (E_OK == eStdRetVal) {

        eRetVal = EA_INTERNAL_JOB_PENDING;
        pEa_State->Ea_eInternalJob = EA_INTERNAL_JOB_INT_PARES_DEV_INFO;
        pEa_State->Ea_eInternalEepJob = EA_INTERNAL_JOB_INT_GET_DEV_INFO;

    }
    else {

        eRetVal = EA_INTERNAL_JOB_FAILED;

    }

    return eRetVal;
}

static Ea_Internal_JobResultType Ea_Internal_JobInt_ParesDevInfo( void )
{
    Ea_Internal_JobResultType eRetVal = EA_INTERNAL_JOB_FAILED;
    Ea_StateType *pEa_State = &Ea_State;
    struct ea_dev *pea_dev = &ea_devices[pEa_State->Ea_uJobIntDevIt];
    struct ea_dev_info *dev_info = (struct ea_dev_info *)(unsigned long int)ea_cache_buff;
    uint16 info_crc = 0U;
    uint32 info_len = 0U;

    /*
     * Check whether the dev info is in a valid status
     * Valid status means that the device is already used as an EA device
     */
    /*PRQA S 2992,2996 2*/
    if (EA_DEV_VALID == dev_info->dev_status) {
        /* Check whether the address range has been modified */
        /*PRQA S 2880 2*/
        if (( dev_info->dev_addr != pea_dev->dev_addr ) ||
                ( dev_info->dev_size != pea_dev->dev_size )) {
            EA_ERROR("EB device configuration and actual info information are inconsistent\n");
            eRetVal = EA_INTERNAL_JOB_FAILED;
            goto out;
        }

        /* Check whether dev info information has been modified */
        info_len = sizeof(dev_info->dev_status) + sizeof(dev_info->dev_addr) + sizeof(
                       dev_info->dev_size) +
                   sizeof(dev_info->major_version) + sizeof(dev_info->minor_version) + sizeof(
                       dev_info->patch_version);
        info_crc = Ea_Crc16((const uint8 *)dev_info, info_len);

        if (dev_info->check_sum != info_crc) {
            EA_ERROR("EA information was modified, crc error\n");
            eRetVal = EA_INTERNAL_JOB_FAILED;
            goto out;
        }

        pEa_State->Ea_uJobIntDevOffset = 0;
        pEa_State->Ea_uJobIntDevSize = 0;
        eRetVal = Ea_Internal_JobInt_GetBlockInfo();
    }
    else {
        /*
         * Invalid status means that the device is not used as an EA device
         * dev info needs to be set
         */
        eRetVal = Ea_Internal_JobInt_SetDevInfo();
    }

out:
    return eRetVal;

}

static Ea_Internal_JobResultType Ea_Internal_JobInt_SetDevInfo( void )
{
    Std_ReturnType eStdRetVal = (Std_ReturnType)E_OK;
    Ea_Internal_JobResultType eRetVal = EA_INTERNAL_JOB_FAILED;
    Ea_StateType *pEa_State = &Ea_State;
    struct ea_dev *pea_dev = &ea_devices[pEa_State->Ea_uJobIntDevIt];
    struct ea_dev_info *dev_info = (struct ea_dev_info *)(unsigned long int)ea_cache_buff;
    uint16 info_crc = 0U;
    uint32 info_len = 0U;

    Mcal_MemSet(dev_info, 0, sizeof(struct ea_dev_info));
    dev_info->dev_status = EA_DEV_VALID;
    dev_info->dev_addr = pea_dev->dev_addr;
    dev_info->dev_size = pea_dev->dev_size;
    dev_info->major_version = pea_dev->major_version;
    dev_info->minor_version = pea_dev->minor_version;
    dev_info->patch_version = pea_dev->patch_version;
    info_len = sizeof(dev_info->dev_status) + sizeof(dev_info->dev_addr) + sizeof(
                   dev_info->dev_size) +
               sizeof(dev_info->major_version) + sizeof(dev_info->minor_version) + sizeof(
                   dev_info->patch_version);
    info_crc = Ea_Crc16((const uint8 *)dev_info, info_len);
    dev_info->check_sum = info_crc;

    eStdRetVal = Ea_Common_Write(pea_dev->dev_addr, (const uint8 *)dev_info,
                                 sizeof(struct ea_dev_info));

    if (E_OK == eStdRetVal) {

        eRetVal = EA_INTERNAL_JOB_PENDING;
        pea_dev->data_end_addr = pea_dev->dev_addr + sizeof(struct ea_dev_info);
        pea_dev->data_info_addr = pea_dev->dev_addr + pea_dev->dev_size - sizeof(
                                      struct ea_dev_info_end);
        pEa_State->Ea_eInternalJob = EA_INTERNAL_JOB_INT_SET_BLOCK_DATA_END;
        pEa_State->Ea_eInternalEepJob = EA_INTERNAL_JOB_INT_SET_DEV_INFO;

    }
    else {

        eRetVal = EA_INTERNAL_JOB_FAILED;

    }

    return eRetVal;
}

static Ea_Internal_JobResultType Ea_Internal_JobInt_SetBlockDataEnd( void )
{
    Std_ReturnType eStdRetVal = (Std_ReturnType)E_OK;
    Ea_Internal_JobResultType eRetVal = EA_INTERNAL_JOB_FAILED;
    Ea_StateType *pEa_State = &Ea_State;
    struct ea_dev *pea_dev = &ea_devices[pEa_State->Ea_uJobIntDevIt];
    struct ea_dev_data_end *data_end = (struct ea_dev_data_end *)(unsigned long int)ea_cache_buff;
    uint16 info_crc = 0U;
    uint32 info_len = 0U;

    Mcal_MemSet(data_end, 0, sizeof(struct ea_dev_data_end));
    data_end->dev_data_end = EA_DEV_DATA_END_FLAG;
    data_end->end_addr = pea_dev->data_end_addr;
    info_len = sizeof(data_end->dev_data_end) + sizeof(data_end->end_addr);
    info_crc = Ea_Crc16((const uint8 *)data_end, info_len);
    data_end->check_sum = info_crc;

    eStdRetVal = Ea_Common_Write(pea_dev->data_end_addr, (const uint8 *)data_end,
                                 sizeof(struct ea_dev_data_end));

    if (E_OK == eStdRetVal) {

        eRetVal = EA_INTERNAL_JOB_PENDING;
        pEa_State->Ea_eInternalJob = EA_INTERNAL_JOB_INT_SET_BLOCK_INFO_END;
        pEa_State->Ea_eInternalEepJob = EA_INTERNAL_JOB_INT_SET_BLOCK_DATA_END;

    }
    else {

        eRetVal = EA_INTERNAL_JOB_FAILED;

    }

    return eRetVal;
}

static Ea_Internal_JobResultType Ea_Internal_JobInt_SetBlockInfoEnd( void )
{
    Std_ReturnType eStdRetVal = (Std_ReturnType)E_OK;
    Ea_Internal_JobResultType eRetVal = EA_INTERNAL_JOB_FAILED;
    Ea_StateType *pEa_State = &Ea_State;
    struct ea_dev *pea_dev = &ea_devices[pEa_State->Ea_uJobIntDevIt];
    struct ea_dev_info_end *info_end = (struct ea_dev_info_end *)(unsigned long int)ea_cache_buff;
    uint16 info_crc = 0U;
    uint32 info_len = 0U;

    Mcal_MemSet(info_end, 0, sizeof(struct ea_dev_info_end));
    info_end->dev_info_end = EA_DEV_DATA_INFO_FLAG;
    info_end->end_addr = pea_dev->data_info_addr;
    info_len = sizeof(info_end->dev_info_end) + sizeof(info_end->end_addr);
    info_crc = Ea_Crc16((const uint8 *)info_end, info_len);
    info_end->check_sum = info_crc;

    eStdRetVal = Ea_Common_Write(pea_dev->data_info_addr, (const uint8 *)info_end,
                                 sizeof(struct ea_dev_info_end));

    if (E_OK == eStdRetVal) {

        eRetVal = EA_INTERNAL_JOB_PENDING;
        pEa_State->Ea_eInternalJob = EA_INTERNAL_JOB_INT_DONE;
        pEa_State->Ea_eInternalEepJob = EA_INTERNAL_JOB_INT_SET_BLOCK_INFO_END;

    }
    else {

        eRetVal = EA_INTERNAL_JOB_FAILED;

    }

    return eRetVal;
}

static Ea_Internal_JobResultType Ea_Internal_JobInt_GetBlockInfo( void )
{
    Std_ReturnType eStdRetVal = (Std_ReturnType)E_OK;
    Ea_Internal_JobResultType eRetVal = EA_INTERNAL_JOB_FAILED;
    Ea_StateType *pEa_State = &Ea_State;
    struct ea_dev *pea_dev = &ea_devices[pEa_State->Ea_uJobIntDevIt];
    uint8 *block_info = (uint8 *)ea_cache_buff;
    Eep_LengthType block_info_size = pea_dev->dev_size -
                                     pEa_State->Ea_uJobIntDevOffset;
    block_info_size = _MIN(block_info_size, EA_DEV_CACHE_SIZE);
    Eep_AddressType block_info_addr = pea_dev->dev_addr + pea_dev->dev_size -
                                      pEa_State->Ea_uJobIntDevOffset - block_info_size;

    if (pEa_State->Ea_uJobIntDevOffset >= pea_dev->dev_size) {
        EA_ERROR("check the entire Ea device, no info end address was found, initialization failed\n");
        EA_ERROR("Ea device dev_index:%d dev_addr:%d dev_size:%d\n",
                 pEa_State->Ea_uJobIntDevIt, pea_dev->dev_addr, pea_dev->dev_size);
        eRetVal = EA_INTERNAL_JOB_FAILED;
        return eRetVal;
    }

    /* Get block information from the end address of the device */
    Mcal_MemSet(block_info, 0, block_info_size);
    eStdRetVal = Ea_Common_Read(block_info_addr, (uint8 *)block_info,
                                block_info_size);

    if (E_OK == eStdRetVal) {

        eRetVal = EA_INTERNAL_JOB_PENDING;
        pEa_State->Ea_uJobIntDevOffset += block_info_size;
        pEa_State->Ea_uJobIntDevSize = block_info_size;
        /* Traverse the record information, the record information grows upward from the tail */
        pEa_State->Ea_uJobIntRecordIndex = pEa_State->Ea_uJobIntDevSize / sizeof(
                                               union ea_record_info_common) - 1;
        pEa_State->Ea_eInternalJob = EA_INTERNAL_JOB_INT_PARES_BLOCK_INFO;
        pEa_State->Ea_eInternalEepJob = EA_INTERNAL_JOB_INT_GET_BACKUP_BLOCK_INFO;

    }
    else {

        eRetVal = EA_INTERNAL_JOB_FAILED;

    }

    return eRetVal;
}

static Ea_Internal_JobResultType Ea_Internal_JobInt_ParesInfoEndFlag(
    struct ea_dev_info_end *info_end )
{
    Ea_Internal_JobResultType eRetVal = EA_INTERNAL_JOB_FAILED;
    Ea_StateType *pEa_State = &Ea_State;
    struct ea_dev *pea_dev = &ea_devices[pEa_State->Ea_uJobIntDevIt];
    uint16 info_crc = 0U;
    uint32 info_len = 0U;

    /* Determine whether info end crc is correct */
    info_len = sizeof(info_end->dev_info_end) + sizeof(info_end->end_addr);
    info_crc = Ea_Crc16((const uint8 *)info_end, info_len);

    if (info_crc != info_end->check_sum) {
        EA_ERROR("EA information end flag was modified, crc error\n");
        eRetVal = EA_INTERNAL_JOB_FAILED;
        goto out;
    }

    /* Update record info end information */
    pea_dev->data_info_addr = info_end->end_addr;
    pea_dev->data_end_addr = _MAX(pea_dev->data_end_addr,
                                  pea_dev->dev_addr + sizeof(struct ea_dev_info));

    /* Get record data end flag */
    eRetVal = Ea_Internal_JobInt_GetDataEndFlag();

out:
    return eRetVal;
}

static Ea_Internal_JobResultType Ea_Internal_JobInt_DiscardRecordInfo(
    struct ea_record_info *record_info, Eep_AddressType block_info_addr)
{
    Std_ReturnType eStdRetVal = (Std_ReturnType)E_OK;
    Ea_Internal_JobResultType eRetVal = EA_INTERNAL_JOB_FAILED;
    Ea_StateType *pEa_State = &Ea_State;

    record_info->record_status = EA_RECORD_DISCARD;
    eStdRetVal = Ea_Common_Write(block_info_addr,
                                 (const uint8 *)record_info, sizeof(struct ea_record_info));

    if (E_OK == eStdRetVal) {

        eRetVal = EA_INTERNAL_JOB_PENDING;
        pEa_State->Ea_eInternalJob = EA_INTERNAL_JOB_INT_BLOCK_INFO_LOOP;
        pEa_State->Ea_eInternalEepJob = EA_INTERNAL_JOB_DONE;

    }
    else {

        eRetVal = EA_INTERNAL_JOB_FAILED;

    }

    return eRetVal;
}

static Ea_Internal_JobResultType Ea_Internal_JobInt_ParesRecordInfo(
    struct ea_record_info *record_info, Eep_AddressType block_info_addr)
{
    Ea_Internal_JobResultType eRetVal = EA_INTERNAL_JOB_FAILED;
    Ea_StateType *pEa_State = &Ea_State;
    struct ea_dev *pea_dev = &ea_devices[pEa_State->Ea_uJobIntDevIt];
    uint16 block_index = 0U;

    /* Update the address at the end of the data */
    pea_dev->data_end_addr = record_info->record_address + ROUNDUP(
                                 record_info->record_size, EA_VIRTUAL_PAGE_SIZE);

    /* discard record info not  */
    if (EA_RECORD_DISCARD == record_info->record_status) {
        EA_ERROR("EA_RECORD_DISCARD record not need to process, block_num:%d\n",
                 record_info->record_num);
        goto loop;
    }

    /* Check if the record is available */
    block_index = Ea_GetBlockIndex(record_info->record_num);

    if (EA_BLOCK_INDEX_DEF == block_index) {
        EA_ERROR("block not EB configuration, block_num:%d discard record info\n",
                 record_info->record_num);
        eRetVal = Ea_Internal_JobInt_DiscardRecordInfo(record_info, block_info_addr);
        goto out;
    }

    switch (record_info->record_status) {
        case EA_RECORD_INVALID:
            if ((record_info->record_num != block_status[block_index].block_number) ||
                    (record_info->record_size != block_status[block_index].block_size)) {
                EA_ERROR("EB configuration and record are inconsistent, and this record will not be used\n");
                EA_ERROR("discard record info, block_num:%d record_size:0x%x block_size:0x%x\n",
                         record_info->record_num, record_info->record_size,
                         block_status[block_index].block_size);
                eRetVal = Ea_Internal_JobInt_DiscardRecordInfo(record_info, block_info_addr);
                goto out;
            }

            block_status[block_index].block_data_addr = record_info->record_address;
            block_status[block_index].block_info_addr = block_info_addr;
            block_status[block_index].block_status = EA_RECORD_INVALID;

            break;

        case EA_RECORD_VALID:
            if ((record_info->record_num != block_status[block_index].block_number) ||
                    (record_info->record_size != block_status[block_index].block_size)) {
                EA_ERROR("EB configuration and record are inconsistent, and this record will not be used\n");
                EA_ERROR("discard record info, block_num:%d record_size:0x%x block_size:0x%x\n",
                         record_info->record_num, record_info->record_size,
                         block_status[block_index].block_size);
                eRetVal = Ea_Internal_JobInt_DiscardRecordInfo(record_info, block_info_addr);
                goto out;
            }

            block_status[block_index].block_data_addr = record_info->record_address;
            block_status[block_index].block_info_addr = block_info_addr;
            block_status[block_index].block_status = EA_RECORD_VALID;
            break;

        case EA_BLOCK_INVALID:
            block_status[block_index].block_data_addr = record_info->record_address;
            block_status[block_index].block_info_addr = block_info_addr;
            block_status[block_index].block_status = EA_BLOCK_INVALID;
            break;

        /*PRQA S 2880 2*/
        case EA_RECORD_DISCARD:
            break;

        default:
            break;
    }

loop:
    eRetVal = Ea_Internal_JobInt_BlockInfoLoop();

out:
    return eRetVal;
}

static Ea_Internal_JobResultType Ea_Internal_JobInt_ParesBlockInfo( void )
{
    Ea_Internal_JobResultType eRetVal = EA_INTERNAL_JOB_FAILED;
    Ea_StateType *pEa_State = &Ea_State;
    struct ea_dev *pea_dev = &ea_devices[pEa_State->Ea_uJobIntDevIt];
    union ea_record_info_common *block_info = (union ea_record_info_common *)
                (unsigned long int)ea_cache_buff;
    struct ea_record_info *record_info = NULL_PTR;
    struct ea_dev_info_end *info_end = NULL_PTR;
    Eep_AddressType block_info_addr = 0;
    uint16 info_index = 0U;

#ifdef EA_DEV_DUMP
    uint16 info_index_max =  pEa_State->Ea_uJobIntDevSize / sizeof(
                                 union ea_record_info_common) - 1;

    if (pEa_State->Ea_uJobIntRecordIndex == info_index_max) {
        hexdump8_ex(ea_cache_buff, pEa_State->Ea_uJobIntDevSize,
                    (uint64)((uint32)ea_cache_buff));
    }

    EA_ERROR("EA Pares Block Info, record index:%d\n",
             pEa_State->Ea_uJobIntRecordIndex);
#endif

    /* Configure the current processing record address */
    info_index = pEa_State->Ea_uJobIntRecordIndex;
    record_info = &block_info[info_index].record_info;
    info_end = &block_info[info_index].info_end;
    block_info_addr = pea_dev->dev_addr + pea_dev->dev_size -
                      pEa_State->Ea_uJobIntDevOffset;
    block_info_addr +=  sizeof(union ea_record_info_common) *  info_index;
    EA_DEBUG("EA Pares Block Info, record index:%d block_info_addr:0x%x\n",
             info_index, block_info_addr);

    /* Determine whether the record is info end */
    if ((EA_DEV_DATA_INFO_FLAG == info_end->dev_info_end)
            && (block_info_addr == info_end->end_addr)) {

        /* Pares record info end flag */
        eRetVal = Ea_Internal_JobInt_ParesInfoEndFlag(info_end);

    }
    else {

        eRetVal = Ea_Internal_JobInt_ParesRecordInfo(record_info, block_info_addr);
    }

    return eRetVal;
}

static Ea_Internal_JobResultType Ea_Internal_JobInt_BlockInfoLoop( void )
{
    Ea_Internal_JobResultType eRetVal = EA_INTERNAL_JOB_FAILED;
    Ea_StateType *pEa_State = &Ea_State;

    /* If the info end flag is not found, continue to traverse the info information */
    if (pEa_State->Ea_uJobIntRecordIndex) {
        pEa_State->Ea_uJobIntRecordIndex--;
        eRetVal = Ea_Internal_JobInt_ParesBlockInfo();
    }
    else {
        eRetVal = Ea_Internal_JobInt_GetBlockInfo();
    }

    return eRetVal;
}

static Ea_Internal_JobResultType Ea_Internal_JobInt_GetDataEndFlag( void )
{
    Std_ReturnType eStdRetVal = (Std_ReturnType)E_OK;
    Ea_Internal_JobResultType eRetVal = EA_INTERNAL_JOB_FAILED;
    Ea_StateType *pEa_State = &Ea_State;
    struct ea_dev *pea_dev = &ea_devices[pEa_State->Ea_uJobIntDevIt];
    struct ea_dev_data_end *data_end = (struct ea_dev_data_end *)(unsigned long int)ea_cache_buff;

    /* Get block data information */
    Mcal_MemSet(data_end, 0, sizeof(struct ea_dev_data_end));
    eStdRetVal = Ea_Common_Read(pea_dev->data_end_addr, (uint8 *)data_end,
                                sizeof(struct ea_dev_data_end));

    if (E_OK == eStdRetVal) {

        eRetVal = EA_INTERNAL_JOB_PENDING;
        pEa_State->Ea_eInternalJob = EA_INTERNAL_JOB_INT_PARES_BLOCK_DATA_END;
        pEa_State->Ea_eInternalEepJob = EA_INTERNAL_JOB_INT_GET_BLOCK_DATA_END;

    }
    else {

        eRetVal = EA_INTERNAL_JOB_FAILED;

    }

    return eRetVal;
}

static Ea_Internal_JobResultType Ea_Internal_JobInt_ParesDataEndFlag( void )
{
    Ea_Internal_JobResultType eRetVal = EA_INTERNAL_JOB_FAILED;
    Ea_StateType *pEa_State = &Ea_State;
    struct ea_dev *pea_dev = &ea_devices[pEa_State->Ea_uJobIntDevIt];
    struct ea_dev_data_end *data_end = (struct ea_dev_data_end *)(unsigned long int)ea_cache_buff;
    uint16 info_crc = 0U;
    uint32 info_len = 0U;

    /*PRQA S 2992,2996 2*/
    if (EA_DEV_DATA_END_FLAG == data_end->dev_data_end) {

        /*PRQA S 2880 2*/
        if (( data_end->end_addr != pea_dev->data_end_addr )) {
            EA_ERROR("Incorrect end address of data\n");
            eRetVal = EA_INTERNAL_JOB_FAILED;
            goto out;
        }

        /* Check whether data end information has been modified */
        info_len = sizeof(data_end->dev_data_end) + sizeof(data_end->end_addr);
        info_crc = Ea_Crc16((const uint8 *)data_end, info_len);

        if (data_end->check_sum != info_crc) {
            EA_ERROR("end address of data information was modified, crc error\n");
            eRetVal = EA_INTERNAL_JOB_FAILED;
            goto out;
        }

        eRetVal = Ea_Internal_JobInt_GetBackupBlockInfo();
    }
    else {

        eRetVal = EA_INTERNAL_JOB_FAILED;

    }

out:
    return eRetVal;
}

static Ea_Internal_JobResultType Ea_Internal_JobInt_GetBackupBlockInfo( void )
{
    Std_ReturnType eStdRetVal = (Std_ReturnType)E_OK;
    Ea_Internal_JobResultType eRetVal = EA_INTERNAL_JOB_FAILED;
    Ea_StateType *pEa_State = &Ea_State;
    struct ea_dev *pea_dev = &ea_devices[pEa_State->Ea_uJobIntDevIt];
    uint8 *record_info = (uint8 *)ea_cache_buff;
    Eep_AddressType backup_info_addr = pea_dev->data_info_addr - sizeof(
                                           struct ea_dev_info_end);

    /* Get block information from the end address of the device */
    Mcal_MemSet(record_info, 0, sizeof(struct ea_record_info));
    eStdRetVal = Ea_Common_Read(backup_info_addr, (uint8 *)record_info,
                                sizeof(struct ea_record_info));

    if (E_OK == eStdRetVal) {

        eRetVal = EA_INTERNAL_JOB_PENDING;
        pEa_State->Ea_eInternalJob = EA_INTERNAL_JOB_INT_PARES_BACKUP_BLOCK_INFO;
        pEa_State->Ea_eInternalEepJob = EA_INTERNAL_JOB_INT_GET_BACKUP_BLOCK_INFO;

    }
    else {

        eRetVal = EA_INTERNAL_JOB_FAILED;

    }

    return eRetVal;
}

static Ea_Internal_JobResultType Ea_Internal_JobInt_ParesBackupBlockInfo( void )
{
    Ea_Internal_JobResultType eRetVal = EA_INTERNAL_JOB_FAILED;
    Ea_StateType *pEa_State = &Ea_State;
    struct ea_block_status *pblock_status = NULL;
    struct ea_dev *pea_dev = NULL;
    struct ea_record_info *record_info = (struct ea_record_info *)
                                         (unsigned long int)ea_cache_buff;
    uint16 block_index = 0U;

    /* Check if the record is available */
    block_index = Ea_GetBlockIndex(record_info->record_num);

    if (EA_BLOCK_INDEX_DEF == block_index) {
        EA_ERROR("backup block not used\n");
        goto INT_DONE;
    }

    /*PRQA S 2992,2996 2*/
    if (EA_RECORD_VALID == record_info->record_status) {

        /*PRQA S 2880 2*/
        if ((record_info->record_num != block_status[block_index].block_number) ||
                (record_info->record_size != block_status[block_index].block_size)) {
            EA_ERROR("EB configuration and record are inconsistent, and this backup record will not be used\n");
            goto INT_DONE;
        }

        pblock_status = &block_status[block_index];
        pea_dev = &ea_devices[pblock_status->dev_index];
        pea_dev->backup_block_active = TRUE;
        pea_dev->backup_block_index  = block_index;
        pea_dev->backup_info_addr = pea_dev->data_info_addr - sizeof(
                                        struct ea_dev_info_end);
        pea_dev->backup_data_addr = record_info->record_address;
        pea_dev->backup_data_size = record_info->record_size;

        if (EA_RECORD_INVALID == block_status[block_index].block_status) {
            pEa_State->Ea_uJobDataOffset = 0;
            pEa_State->Ea_uJobDataSize = 0;
            pEa_State->Ea_uBackupBlockIndex = block_index;
            eRetVal = Ea_Internal_JobInt_ReadBackupBlockData();
        }
        else {
            EA_ERROR("backup block original record not record invalid\n");
            goto INT_DONE;
        }
    }
    else {
        EA_ERROR("backup block not valid\n");
        goto INT_DONE;
    }

    /*PRQA S 2880 2*/
    return eRetVal;

INT_DONE:
    eRetVal = Ea_Internal_JobInt_Done();
    return eRetVal;

}

static Ea_Internal_JobResultType Ea_Internal_JobInt_ReadBackupBlockData( void )
{
    Std_ReturnType eStdRetVal = (Std_ReturnType)E_OK;
    Ea_Internal_JobResultType eRetVal = EA_INTERNAL_JOB_FAILED;
    Ea_StateType *pEa_State = &Ea_State;
    uint8 *record_data = (uint8 *)ea_cache_buff;
    struct ea_block_status *pblock_status =
            &block_status[pEa_State->Ea_uBackupBlockIndex];
    struct ea_dev *pea_dev = &ea_devices[pblock_status->dev_index];

    pEa_State->Ea_uJobDataSize = _MIN(EA_DEV_CACHE_SIZE,
                                      (ROUNDUP(pea_dev->backup_data_size,
                                              EA_VIRTUAL_PAGE_SIZE) - pEa_State->Ea_uJobDataOffset));
    Mcal_MemSet(record_data, 0x0, pEa_State->Ea_uJobDataSize);
    eStdRetVal = Ea_Common_Read(pea_dev->backup_data_addr +
                                pEa_State->Ea_uJobDataOffset,
                                record_data, pEa_State->Ea_uJobDataSize);

    if (E_OK == eStdRetVal) {

        eRetVal = EA_INTERNAL_JOB_PENDING;
        pEa_State->Ea_eInternalJob = EA_INTERNAL_JOB_INT_SYNC_BACKUP_BLOCK_DATA;
        pEa_State->Ea_eInternalEepJob = EA_INTERNAL_JOB_INT_READ_BACKUP_BLOCK_DATA;

    }
    else {

        eRetVal = EA_INTERNAL_JOB_FAILED;

    }

    return eRetVal;
}

static Ea_Internal_JobResultType Ea_Internal_JobInt_SyncBackupBlockData( void )
{
    Std_ReturnType eStdRetVal = (Std_ReturnType)E_OK;
    Ea_Internal_JobResultType eRetVal = EA_INTERNAL_JOB_FAILED;
    Ea_StateType *pEa_State = &Ea_State;
    uint8 *record_data = (uint8 *)ea_cache_buff;
    struct ea_block_status *pblock_status =
            &block_status[pEa_State->Ea_uBackupBlockIndex];
    struct ea_dev *pea_dev = &ea_devices[pblock_status->dev_index];

    eStdRetVal = Ea_Common_Write(pblock_status->block_data_addr +
                                 pEa_State->Ea_uJobDataOffset,
                                 record_data, pEa_State->Ea_uJobDataSize);

    if (E_OK == eStdRetVal) {

        eRetVal = EA_INTERNAL_JOB_PENDING;
        pEa_State->Ea_uJobDataOffset += pEa_State->Ea_uJobDataSize;

        pEa_State->Ea_eInternalEepJob = EA_INTERNAL_JOB_INT_SYNC_BACKUP_BLOCK_DATA;

        if (pEa_State->Ea_uJobDataOffset >= pea_dev->backup_data_size) {
            pEa_State->Ea_eInternalJob = EA_INTERNAL_JOB_INT_BACKUP_BLOCK_ACTIVE;
        }
        else {
            pEa_State->Ea_eInternalJob = EA_INTERNAL_JOB_INT_READ_BACKUP_BLOCK_DATA;
        }

    }
    else {

        eRetVal = EA_INTERNAL_JOB_FAILED;

    }

    return eRetVal;
}

static Ea_Internal_JobResultType Ea_Internal_JobInt_BackupBlockActive( void )
{
    Std_ReturnType eStdRetVal = (Std_ReturnType)E_OK;
    Ea_Internal_JobResultType eRetVal = EA_INTERNAL_JOB_FAILED;
    Ea_StateType *pEa_State = &Ea_State;
    struct ea_block_status *pblock_status =
            &block_status[pEa_State->Ea_uBackupBlockIndex];
    struct ea_record_info *record_info = (struct ea_record_info *)(unsigned long int)ea_cache_buff;

    Mcal_MemSet(record_info, 0, sizeof(struct ea_record_info));
    record_info->record_status = EA_RECORD_VALID;
    record_info->record_num = pblock_status->block_number;
    record_info->record_size = pblock_status->block_size;
    record_info->record_address = pblock_status->block_data_addr;
    eStdRetVal = Ea_Common_Write(pblock_status->block_info_addr,
                                 (const uint8 *)record_info, sizeof(struct ea_record_info));

    if (E_OK == eStdRetVal) {

        eRetVal = EA_INTERNAL_JOB_PENDING;
        pblock_status->block_status = EA_RECORD_VALID;
        pEa_State->Ea_eInternalJob = EA_INTERNAL_JOB_INT_DONE;
        pEa_State->Ea_eInternalEepJob = EA_INTERNAL_JOB_INT_BACKUP_BLOCK_ACTIVE;

    }
    else {

        eRetVal = EA_INTERNAL_JOB_FAILED;

    }

    return eRetVal;
}

static Ea_Internal_JobResultType Ea_Internal_JobInt_Done( void )
{
    Ea_Internal_JobResultType eRetVal = EA_INTERNAL_JOB_FAILED;
    Ea_StateType *pEa_State = &Ea_State;

    pEa_State->Ea_uJobIntDevIt++;

    if (EA_DEV_NUMBER == pEa_State->Ea_uJobIntDevIt) {

        eRetVal = Ea_Internal_Job_Done();

    }
    else {

        eRetVal = Ea_Internal_JobInt_GetDevInfo();
    }

    return eRetVal;
}

static Ea_Internal_JobResultType Ea_Internal_Job_Done( void )
{
    Ea_Internal_JobResultType eRetVal = EA_INTERNAL_JOB_OK;

    return eRetVal;
}

static MemIf_JobResultType Ea_JobRead( void )
{
    MemIf_JobResultType eRetVal = MEMIF_JOB_FAILED;
    Ea_StateType *pEa_State = &Ea_State;
    struct ea_block_status *pblock_status =
            &block_status[pEa_State->Ea_uJobBlockIndex];

    switch (pblock_status->block_status) {
        case EA_RECORD_UNSET:
            EA_DEBUG("block in unset status, BlockIndex:%d BlockNumber:%d\n",
                     pEa_State->Ea_uJobBlockIndex, pEa_State->Ea_uJobBlockNumber);
            eRetVal = MEMIF_BLOCK_INCONSISTENT;
            break;

        case EA_RECORD_INVALID:
            EA_DEBUG("block record in invalid status, BlockIndex:%d BlockNumber:%d\n",
                     pEa_State->Ea_uJobBlockIndex, pEa_State->Ea_uJobBlockNumber);
            eRetVal = MEMIF_BLOCK_INCONSISTENT;
            break;

        case EA_BLOCK_INVALID:
            EA_DEBUG("block in invalid status, BlockIndex:%d BlockNumber:%d\n",
                     pEa_State->Ea_uJobBlockIndex, pEa_State->Ea_uJobBlockNumber);
            eRetVal = MEMIF_BLOCK_INVALID;
            break;

        case EA_RECORD_VALID:
            eRetVal = Ea_JobRead_Data();
            break;

        default:
            EA_ERROR("block in unknown state, BlockIndex:%d BlockNumber:%d\n",
                     pEa_State->Ea_uJobBlockIndex, pEa_State->Ea_uJobBlockNumber);
            eRetVal = MEMIF_JOB_FAILED;
    }

    return eRetVal;
}

static MemIf_JobResultType Ea_JobRead_Data( void )
{
    Std_ReturnType eStdRetVal = (Std_ReturnType)E_OK;
    MemIf_JobResultType eRetVal = MEMIF_JOB_FAILED;
    Ea_StateType *pEa_State = &Ea_State;
    struct ea_block_status *pblock_status =
            &block_status[pEa_State->Ea_uJobBlockIndex];

    eStdRetVal = Ea_Common_Read(pblock_status->block_data_addr +
                                pEa_State->Ea_uJobBlockOffset,
                                pEa_State->Ea_pJobReadDataDestPtr, pEa_State->Ea_uJobBlockLength);

    if (E_OK == eStdRetVal) {

        eRetVal = MEMIF_JOB_PENDING;
        pEa_State->Ea_eJob = EA_JOB_DONE;
        pEa_State->Ea_eEepJob = EA_JOB_READ_DATA;

    }
    else {

        eRetVal = MEMIF_JOB_FAILED;

    }

    return eRetVal;
}

MemIf_JobResultType Ea_JobWrite_BackupBlockInfo( void )
{
    MemIf_JobResultType eRetVal = MEMIF_JOB_OK;
    Ea_StateType *pEa_State = &Ea_State;
    struct ea_block_status *pblock_status =
            &block_status[pEa_State->Ea_uJobBlockIndex];
    struct ea_dev *pea_dev = &ea_devices[pblock_status->dev_index];
    struct ea_block_status *pblock_status_backup =
            &block_status_backup[pEa_State->Ea_uJobBlockIndex];
    struct ea_dev *pea_backup_dev = &ea_backup_devices[pblock_status->dev_index];

    Mcal_MemCpy(pblock_status_backup, pblock_status,
                sizeof(struct ea_block_status));
    Mcal_MemCpy(pea_backup_dev, pea_dev, sizeof(struct ea_dev));

    return eRetVal;
}

MemIf_JobResultType Ea_JobWrite_SyncBlockInfo( void )
{
    MemIf_JobResultType eRetVal = MEMIF_JOB_OK;
    Ea_StateType *pEa_State = &Ea_State;
    struct ea_block_status *pblock_status =
            &block_status[pEa_State->Ea_uJobBlockIndex];
    struct ea_dev *pea_dev = &ea_devices[pblock_status->dev_index];
    struct ea_block_status *pblock_status_backup =
            &block_status_backup[pEa_State->Ea_uJobBlockIndex];
    struct ea_dev *pea_backup_dev = &ea_backup_devices[pblock_status->dev_index];

    if (pblock_status->block_status == EA_RECORD_INVALID
            && pblock_status_backup->block_status != EA_RECORD_UNSET) {
        pblock_status_backup->block_status = pblock_status->block_status;
    }

    Mcal_MemCpy(pblock_status, pblock_status_backup,
                sizeof(struct ea_block_status));
    Mcal_MemCpy(pea_dev, pea_backup_dev, sizeof(struct ea_dev));

    return eRetVal;
}

static MemIf_JobResultType Ea_JobWrite( void )
{
    MemIf_JobResultType eRetVal = MEMIF_JOB_FAILED;
    Ea_StateType *pEa_State = &Ea_State;
    struct ea_block_status *pblock_status =
            &block_status[pEa_State->Ea_uJobBlockIndex];
    struct ea_dev *pea_dev = &ea_devices[pblock_status->dev_index];
    Eep_LengthType dev_free_size = 0;
    Eep_LengthType block_record_size = 0;

    Ea_JobWrite_BackupBlockInfo();

    switch (pblock_status->block_status) {
        case EA_RECORD_UNSET:
            EA_DEBUG("block in unset status, BlockIndex:%d BlockNumber:%d\n",
                     pEa_State->Ea_uJobBlockIndex, pEa_State->Ea_uJobBlockNumber);

            block_record_size = sizeof(struct ea_record_info) + ROUNDUP(
                                    pblock_status->block_size, EA_VIRTUAL_PAGE_SIZE);
            dev_free_size = pea_dev->data_info_addr - pea_dev->data_end_addr - sizeof(
                                struct ea_dev_data_end);

            if (block_record_size > dev_free_size) {

                EA_ERROR("EA free space does not meet the block record size, BlockIndex:%d BlockNumber:%d\n",
                         pEa_State->Ea_uJobBlockIndex, pEa_State->Ea_uJobBlockNumber);
                EA_ERROR("block_size:0x%x block_record_size:0x%x data_info_addr:0x%x data_end_addr:0x%x dev_free_size:0x%x\n",
                         pblock_status->block_size, block_record_size, pea_dev->data_info_addr,
                         pea_dev->data_end_addr, dev_free_size);
                eRetVal = MEMIF_JOB_FAILED;
                break;

            }

            if (pea_dev->backup_block_active) {
                block_record_size += sizeof(struct ea_record_info) + ROUNDUP(
                                         pea_dev->backup_data_size, EA_VIRTUAL_PAGE_SIZE);

                if (block_record_size > dev_free_size) {

                    EA_ERROR("EA free space does not meet the block backup record size, discard backup data");
                    eRetVal = Ea_JobWrite_BlockInfoEnd();
                }
                else {
                    pEa_State->Ea_uBackupBlockIndex = pea_dev->backup_block_index;
                    pEa_State->Ea_uJobMoveDataOffset = ROUNDUP(pblock_status->block_size,
                                                       EA_VIRTUAL_PAGE_SIZE);
                    eRetVal = Ea_JobWrite_MoveBackupRecordInfo();
                }
            }
            else {
                eRetVal = Ea_JobWrite_BlockInfoEnd();
            }

            break;

        case EA_BLOCK_INVALID:
            EA_DEBUG("block in invalid status, BlockIndex:%d BlockNumber:%d\n",
                     pEa_State->Ea_uJobBlockIndex, pEa_State->Ea_uJobBlockNumber);
            eRetVal = MEMIF_BLOCK_INVALID;
            break;

        case EA_RECORD_INVALID:
            eRetVal = Ea_JobWrite_RecordInfo();
            break;

        case EA_RECORD_VALID:
            if (Ea_BlockConfig[pEa_State->Ea_uJobBlockIndex].backupData) {

                block_record_size = sizeof(struct ea_record_info) + ROUNDUP(
                                        pblock_status->block_size, EA_VIRTUAL_PAGE_SIZE);
                dev_free_size = pea_dev->data_info_addr - pea_dev->data_end_addr - sizeof(
                                    struct ea_dev_data_end);

                if (block_record_size > dev_free_size) {

                    EA_ERROR("EA free space does not meet the block backup record size, BlockIndex:%d BlockNumber:%d\n",
                             pEa_State->Ea_uJobBlockIndex, pEa_State->Ea_uJobBlockNumber);
                    EA_ERROR("block_size:0x%x block_record_size:0x%x data_info_addr:0x%x data_end_addr:0x%x dev_free_size:0x%x\n",
                             pblock_status->block_size, block_record_size, pea_dev->data_info_addr,
                             pea_dev->data_end_addr, dev_free_size);
                    eRetVal = Ea_JobWrite_RecordInfo();
                }
                else {
                    eRetVal = Ea_JobWrite_BackupRecordInfo();

                }
            }
            else {
                eRetVal = Ea_JobWrite_RecordInfo();
            }

            break;

        default:
            EA_ERROR("block in unknown state, BlockIndex:%d BlockNumber:%d\n",
                     pEa_State->Ea_uJobBlockIndex, pEa_State->Ea_uJobBlockNumber);
            eRetVal = MEMIF_JOB_FAILED;
    }

    return eRetVal;
}

static MemIf_JobResultType Ea_JobWrite_BackupRecordInfo( void )
{
    Std_ReturnType eStdRetVal = (Std_ReturnType)E_OK;
    MemIf_JobResultType eRetVal = MEMIF_JOB_FAILED;
    Ea_StateType *pEa_State = &Ea_State;
    struct ea_block_status *pblock_status =
            &block_status[pEa_State->Ea_uJobBlockIndex];
    struct ea_record_info *record_info = (struct ea_record_info *)(unsigned long int)ea_cache_buff;
    struct ea_dev *pea_dev = &ea_devices[pblock_status->dev_index];
    Eep_AddressType backup_info_addr = 0;

    Mcal_MemSet(record_info, 0, sizeof(struct ea_record_info));
    record_info->record_status = EA_RECORD_INVALID;
    record_info->record_num = pblock_status->block_number;
    record_info->record_size = pblock_status->block_size;
    record_info->record_address = pea_dev->data_end_addr + sizeof(
                                      struct ea_dev_data_end);
    backup_info_addr = pea_dev->data_info_addr - sizeof(struct ea_dev_info_end);
    eStdRetVal = Ea_Common_Write(backup_info_addr,
                                 (const uint8 *)record_info, sizeof(struct ea_record_info));

    if (E_OK == eStdRetVal) {

        eRetVal = MEMIF_JOB_PENDING;
        pEa_State->Ea_uJobDataOffset = 0;
        pEa_State->Ea_uJobDataSize = 0;
        pea_dev->backup_block_active = FALSE;
        pEa_State->Ea_eJob = EA_JOB_WRITE_READ_BACKUP_RECORD_DATA;
        pEa_State->Ea_eEepJob = EA_JOB_WRITE_BACKUP_RECORD_INFO;
    }
    else {

        Ea_JobWrite_SyncBlockInfo();
        eRetVal = MEMIF_JOB_FAILED;

    }

    return eRetVal;
}

static MemIf_JobResultType Ea_JobWrite_ReadBackupRecordData( void )
{
    Std_ReturnType eStdRetVal = (Std_ReturnType)E_OK;
    MemIf_JobResultType eRetVal = MEMIF_JOB_FAILED;
    Ea_StateType *pEa_State = &Ea_State;
    struct ea_block_status *pblock_status =
            &block_status[pEa_State->Ea_uJobBlockIndex];
    uint8 *record_data = (uint8 *)ea_cache_buff;

    pEa_State->Ea_uJobDataSize = _MIN(EA_DEV_CACHE_SIZE,
                                      (ROUNDUP(pblock_status->block_size,
                                              EA_VIRTUAL_PAGE_SIZE) - pEa_State->Ea_uJobDataOffset));
    Mcal_MemSet(record_data, 0, pEa_State->Ea_uJobDataSize);
    eStdRetVal = Ea_Common_Read(pblock_status->block_data_addr +
                                pEa_State->Ea_uJobDataOffset,
                                record_data, pEa_State->Ea_uJobDataSize);

    if (E_OK == eStdRetVal) {

        eRetVal = MEMIF_JOB_PENDING;
        pEa_State->Ea_eJob = EA_JOB_WRITE_SYNC_BACKUP_RECORD_DATA;
        pEa_State->Ea_eEepJob = EA_JOB_WRITE_READ_BACKUP_RECORD_DATA;

    }
    else {

        Ea_JobWrite_SyncBlockInfo();
        eRetVal = MEMIF_JOB_FAILED;

    }

    return eRetVal;
}

static MemIf_JobResultType Ea_JobWrite_SyncBackupRecordData( void )
{
    Std_ReturnType eStdRetVal = (Std_ReturnType)E_OK;
    MemIf_JobResultType eRetVal = MEMIF_JOB_FAILED;
    Ea_StateType *pEa_State = &Ea_State;
    struct ea_block_status *pblock_status =
            &block_status[pEa_State->Ea_uJobBlockIndex];
    struct ea_dev *pea_dev = &ea_devices[pblock_status->dev_index];
    uint8 *record_data = (uint8 *)ea_cache_buff;
    Eep_AddressType backup_data_addr = 0;

    backup_data_addr = pea_dev->data_end_addr + sizeof(struct ea_dev_data_end);
    eStdRetVal = Ea_Common_Write(backup_data_addr + pEa_State->Ea_uJobDataOffset,
                                 record_data, pEa_State->Ea_uJobDataSize);

    if (E_OK == eStdRetVal) {

        eRetVal = MEMIF_JOB_PENDING;
        pEa_State->Ea_uJobDataOffset += pEa_State->Ea_uJobDataSize;

        pEa_State->Ea_eEepJob = EA_JOB_WRITE_SYNC_BACKUP_RECORD_DATA;

        if (pEa_State->Ea_uJobDataOffset >= pblock_status->block_size) {
            pEa_State->Ea_eJob = EA_JOB_WRITE_BACKUP_RECORD_ACTIVE;
        }
        else {
            pEa_State->Ea_eJob = EA_JOB_WRITE_READ_BACKUP_RECORD_DATA;
        }

    }
    else {

        Ea_JobWrite_SyncBlockInfo();
        eRetVal = MEMIF_JOB_FAILED;

    }

    return eRetVal;
}

static MemIf_JobResultType Ea_JobWrite_BackupRecordActive( void )
{
    Std_ReturnType eStdRetVal = (Std_ReturnType)E_OK;
    MemIf_JobResultType eRetVal = MEMIF_JOB_FAILED;
    Ea_StateType *pEa_State = &Ea_State;
    struct ea_block_status *pblock_status =
            &block_status[pEa_State->Ea_uJobBlockIndex];
    struct ea_record_info *record_info = (struct ea_record_info *)(unsigned long int)ea_cache_buff;
    struct ea_dev *pea_dev = &ea_devices[pblock_status->dev_index];
    Eep_AddressType backup_info_addr = 0;

    Mcal_MemSet(record_info, 0, sizeof(struct ea_record_info));
    record_info->record_status = EA_RECORD_VALID;
    record_info->record_num = pblock_status->block_number;
    record_info->record_size = pblock_status->block_size;
    record_info->record_address = pea_dev->data_end_addr + sizeof(
                                      struct ea_dev_data_end);
    backup_info_addr = pea_dev->data_info_addr - sizeof(struct ea_dev_info_end);
    eStdRetVal = Ea_Common_Write(backup_info_addr,
                                 (const uint8 *)record_info, sizeof(struct ea_record_info));

    if (E_OK == eStdRetVal) {

        pea_dev->backup_block_active = TRUE;
        pea_dev->backup_block_index = pEa_State->Ea_uJobBlockIndex;
        pea_dev->backup_info_addr = backup_info_addr;
        pea_dev->backup_data_addr = record_info->record_address;
        pea_dev->backup_data_size = record_info->record_size;

        eRetVal = MEMIF_JOB_PENDING;
        pEa_State->Ea_eJob = EA_JOB_WRITE_RECORD_INFO;
        pEa_State->Ea_eEepJob = EA_JOB_WRITE_BACKUP_RECORD_ACTIVE;

    }
    else {

        Ea_JobWrite_SyncBlockInfo();
        eRetVal = MEMIF_JOB_FAILED;

    }

    return eRetVal;
}

static MemIf_JobResultType Ea_JobWrite_MoveBackupRecordInfo( void )
{
    Std_ReturnType eStdRetVal = (Std_ReturnType)E_OK;
    MemIf_JobResultType eRetVal = MEMIF_JOB_FAILED;
    Ea_StateType *pEa_State = &Ea_State;
    struct ea_block_status *pblock_status =
            &block_status[pEa_State->Ea_uBackupBlockIndex];
    struct ea_dev *pea_dev = &ea_devices[pblock_status->dev_index];
    struct ea_record_info *record_info = (struct ea_record_info *)(unsigned long int)ea_cache_buff;
    Eep_AddressType backup_info_addr = 0;

    Mcal_MemSet(record_info, 0, sizeof(struct ea_record_info));
    record_info->record_status = EA_RECORD_INVALID;
    record_info->record_num = pblock_status->block_number;
    record_info->record_size = pblock_status->block_size;
    record_info->record_address = pea_dev->backup_data_addr +
                                  pEa_State->Ea_uJobMoveDataOffset;
    backup_info_addr = pea_dev->backup_info_addr - sizeof(struct ea_record_info);
    eStdRetVal = Ea_Common_Write(backup_info_addr,
                                 (const uint8 *)record_info, sizeof(struct ea_record_info));

    if (E_OK == eStdRetVal) {

        eRetVal = MEMIF_JOB_PENDING;
        pEa_State->Ea_uJobDataOffset = 0;
        pEa_State->Ea_uJobDataSize = 0;
        pea_dev->backup_block_active = FALSE;
        pEa_State->Ea_eJob = EA_JOB_WRITE_MOVE_READ_BACKUP_RECORD_DATA;
        pEa_State->Ea_eEepJob = EA_JOB_WRITE_MOVE_BACKUP_RECORD_INFO;
    }
    else {

        Ea_JobWrite_SyncBlockInfo();
        eRetVal = MEMIF_JOB_FAILED;

    }

    return eRetVal;
}

static MemIf_JobResultType Ea_JobWrite_MoveReadBackupRecordData( void )
{
    Std_ReturnType eStdRetVal = (Std_ReturnType)E_OK;
    MemIf_JobResultType eRetVal = MEMIF_JOB_FAILED;
    Ea_StateType *pEa_State = &Ea_State;
    struct ea_block_status *pblock_status =
            &block_status[pEa_State->Ea_uBackupBlockIndex];
    struct ea_dev *pea_dev = &ea_devices[pblock_status->dev_index];
    uint8 *record_data = (uint8 *)ea_cache_buff;
    Eep_AddressType backup_data_addr = 0;

    pEa_State->Ea_uJobDataSize = _MIN(EA_DEV_CACHE_SIZE,
                                      (ROUNDUP(pea_dev->backup_data_size,
                                              EA_VIRTUAL_PAGE_SIZE) - pEa_State->Ea_uJobDataOffset));
    backup_data_addr = pea_dev->backup_data_addr + ROUNDUP(
                           pea_dev->backup_data_size,
                           EA_VIRTUAL_PAGE_SIZE) - pEa_State->Ea_uJobDataOffset -
                       pEa_State->Ea_uJobDataSize;
    Mcal_MemSet(record_data, 0, pEa_State->Ea_uJobDataSize);
    eStdRetVal = Ea_Common_Read(backup_data_addr, record_data,
                                pEa_State->Ea_uJobDataSize);

    if (E_OK == eStdRetVal) {

        eRetVal = MEMIF_JOB_PENDING;
        pEa_State->Ea_eJob = EA_JOB_WRITE_MOVE_SYNC_BACKUP_RECORD_DATA;
        pEa_State->Ea_eEepJob = EA_JOB_WRITE_MOVE_READ_BACKUP_RECORD_DATA;

    }
    else {

        Ea_JobWrite_SyncBlockInfo();
        eRetVal = MEMIF_JOB_FAILED;

    }

    return eRetVal;
}

static MemIf_JobResultType Ea_JobWrite_MoveSyncBackupRecordData( void )
{
    Std_ReturnType eStdRetVal = (Std_ReturnType)E_OK;
    MemIf_JobResultType eRetVal = MEMIF_JOB_FAILED;
    Ea_StateType *pEa_State = &Ea_State;
    struct ea_block_status *pblock_status =
            &block_status[pEa_State->Ea_uBackupBlockIndex];
    struct ea_dev *pea_dev = &ea_devices[pblock_status->dev_index];
    uint8 *record_data = (uint8 *)ea_cache_buff;
    Eep_AddressType backup_data_addr = 0;

    backup_data_addr = pea_dev->backup_data_addr + pEa_State->Ea_uJobMoveDataOffset;
    backup_data_addr = backup_data_addr + ROUNDUP(pea_dev->backup_data_size,
                       EA_VIRTUAL_PAGE_SIZE) - pEa_State->Ea_uJobDataOffset -
                       pEa_State->Ea_uJobDataSize;
    eStdRetVal = Ea_Common_Write(backup_data_addr, record_data,
                                 pEa_State->Ea_uJobDataSize);

    if (E_OK == eStdRetVal) {

        eRetVal = MEMIF_JOB_PENDING;
        pEa_State->Ea_uJobDataOffset += pEa_State->Ea_uJobDataSize;

        pEa_State->Ea_eEepJob = EA_JOB_WRITE_MOVE_SYNC_BACKUP_RECORD_DATA;

        if (pEa_State->Ea_uJobDataOffset >= pea_dev->backup_data_size) {
            pEa_State->Ea_eJob = EA_JOB_WRITE_MOVE_BACKUP_RECORD_ACTIVE;
        }
        else {
            pEa_State->Ea_eJob = EA_JOB_WRITE_MOVE_READ_BACKUP_RECORD_DATA;
        }

    }
    else {

        Ea_JobWrite_SyncBlockInfo();
        eRetVal = MEMIF_JOB_FAILED;

    }

    return eRetVal;
}

static MemIf_JobResultType Ea_JobWrite_MoveBackupRecordActive( void )
{
    Std_ReturnType eStdRetVal = (Std_ReturnType)E_OK;
    MemIf_JobResultType eRetVal = MEMIF_JOB_FAILED;
    Ea_StateType *pEa_State = &Ea_State;
    struct ea_block_status *pblock_status =
            &block_status[pEa_State->Ea_uBackupBlockIndex];
    struct ea_dev *pea_dev = &ea_devices[pblock_status->dev_index];
    struct ea_record_info *record_info = (struct ea_record_info *)(unsigned long int)ea_cache_buff;
    Eep_AddressType backup_info_addr = 0;

    Mcal_MemSet(record_info, 0, sizeof(struct ea_record_info));
    record_info->record_status = EA_RECORD_VALID;
    record_info->record_num = pblock_status->block_number;
    record_info->record_size = pblock_status->block_size;
    record_info->record_address = pea_dev->backup_data_addr +
                                  pEa_State->Ea_uJobMoveDataOffset;
    backup_info_addr = pea_dev->backup_info_addr - sizeof(struct ea_record_info);
    eStdRetVal = Ea_Common_Write(backup_info_addr,
                                 (const uint8 *)record_info, sizeof(struct ea_record_info));

    if (E_OK == eStdRetVal) {

        pea_dev->backup_block_active = TRUE;
        pea_dev->backup_info_addr = backup_info_addr;
        pea_dev->backup_data_addr = record_info->record_address;
        pea_dev->backup_data_size = record_info->record_size;

        eRetVal = MEMIF_JOB_PENDING;
        pEa_State->Ea_eJob = EA_JOB_WRITE_BLOCK_INFO_END;
        pEa_State->Ea_eEepJob = EA_JOB_WRITE_MOVE_BACKUP_RECORD_ACTIVE;

    }
    else {

        Ea_JobWrite_SyncBlockInfo();
        eRetVal = MEMIF_JOB_FAILED;

    }

    return eRetVal;
}

static MemIf_JobResultType Ea_JobWrite_BlockInfoEnd( void )
{
    Std_ReturnType eStdRetVal = (Std_ReturnType)E_OK;
    MemIf_JobResultType eRetVal = MEMIF_JOB_FAILED;
    Ea_StateType *pEa_State = &Ea_State;
    struct ea_block_status *pblock_status =
            &block_status[pEa_State->Ea_uJobBlockIndex];
    struct ea_dev *pea_dev = &ea_devices[pblock_status->dev_index];
    struct ea_dev_info_end *info_end = (struct ea_dev_info_end *)(unsigned long int)ea_cache_buff;
    Eep_AddressType new_end_addr = 0;
    uint16 info_crc = 0U;
    uint32 info_len = 0U;

    Mcal_MemSet(info_end, 0, sizeof(struct ea_dev_info_end));
    new_end_addr = pea_dev->data_info_addr - sizeof(struct ea_dev_info_end);
    info_end->dev_info_end = EA_DEV_DATA_INFO_FLAG;
    info_end->end_addr = new_end_addr;
    info_len = sizeof(info_end->dev_info_end) + sizeof(info_end->end_addr);
    info_crc = Ea_Crc16((const uint8 *)info_end, info_len);
    info_end->check_sum = info_crc;

    eStdRetVal = Ea_Common_Write(new_end_addr, (const uint8 *)info_end,
                                 sizeof(struct ea_dev_info_end));

    if (E_OK == eStdRetVal) {

        eRetVal = MEMIF_JOB_PENDING;
        pblock_status->block_info_addr = pea_dev->data_info_addr;
        pea_dev->data_info_addr = new_end_addr;
        pEa_State->Ea_eJob = EA_JOB_WRITE_RECORD_INFO;
        pEa_State->Ea_eEepJob = EA_JOB_WRITE_BLOCK_INFO_END;

    }
    else {

        Ea_JobWrite_SyncBlockInfo();
        eRetVal = MEMIF_JOB_FAILED;

    }

    return eRetVal;
}

static MemIf_JobResultType Ea_JobWrite_RecordInfo( void )
{
    Std_ReturnType eStdRetVal = (Std_ReturnType)E_OK;
    MemIf_JobResultType eRetVal = MEMIF_JOB_FAILED;
    Ea_StateType *pEa_State = &Ea_State;
    struct ea_block_status *pblock_status =
            &block_status[pEa_State->Ea_uJobBlockIndex];
    struct ea_record_info *record_info = (struct ea_record_info *)(unsigned long int)ea_cache_buff;

    Mcal_MemSet(record_info, 0, sizeof(struct ea_record_info));
    record_info->record_status = EA_RECORD_INVALID;
    record_info->record_num = pblock_status->block_number;
    record_info->record_size = pblock_status->block_size;
    record_info->record_address = pblock_status->block_data_addr;
    eStdRetVal = Ea_Common_Write(pblock_status->block_info_addr,
                                 (const uint8 *)record_info, sizeof(struct ea_record_info));

    if (E_OK == eStdRetVal) {

        eRetVal = MEMIF_JOB_PENDING;

        pEa_State->Ea_eEepJob = EA_JOB_WRITE_RECORD_INFO;

        if (EA_RECORD_UNSET == pblock_status->block_status) {

            pEa_State->Ea_eJob = EA_JOB_WRITE_BLOCK_DATA_END;
            pblock_status->block_status = EA_RECORD_INVALID;

        }
        else {

            pEa_State->Ea_eJob = EA_JOB_WRITE_RECORD_DATA;
            pblock_status->block_status = EA_RECORD_INVALID;

        }


    }
    else {

        Ea_JobWrite_SyncBlockInfo();
        eRetVal = MEMIF_JOB_FAILED;

    }

    return eRetVal;
}

static MemIf_JobResultType Ea_JobWrite_BlockDataEnd( void )
{
    Std_ReturnType eStdRetVal = (Std_ReturnType)E_OK;
    MemIf_JobResultType eRetVal = MEMIF_JOB_FAILED;
    Ea_StateType *pEa_State = &Ea_State;
    struct ea_block_status *pblock_status =
            &block_status[pEa_State->Ea_uJobBlockIndex];
    struct ea_dev *pea_dev = &ea_devices[pblock_status->dev_index];
    struct ea_dev_data_end *data_end = (struct ea_dev_data_end *)(unsigned long int)ea_cache_buff;
    Eep_AddressType new_end_addr = 0;
    uint16 info_crc = 0U;
    uint32 info_len = 0U;

    Mcal_MemSet(data_end, 0, sizeof(struct ea_dev_data_end));
    new_end_addr = pea_dev->data_end_addr + ROUNDUP(pblock_status->block_size,
                   EA_VIRTUAL_PAGE_SIZE);
    data_end->dev_data_end = EA_DEV_DATA_END_FLAG;
    data_end->end_addr = new_end_addr;
    info_len = sizeof(data_end->dev_data_end) + sizeof(data_end->end_addr);
    info_crc = Ea_Crc16((const uint8 *)data_end, info_len);
    data_end->check_sum = info_crc;

    eStdRetVal = Ea_Common_Write(new_end_addr, (const uint8 *)data_end,
                                 sizeof(struct ea_dev_data_end));

    if (E_OK == eStdRetVal) {

        eRetVal = MEMIF_JOB_PENDING;
        pblock_status->block_data_addr = pea_dev->data_end_addr;
        pea_dev->data_end_addr = new_end_addr;
        pEa_State->Ea_eJob = EA_JOB_WRITE_RECORD_DATA;
        pEa_State->Ea_eEepJob = EA_JOB_WRITE_BLOCK_DATA_END;

    }
    else {

        Ea_JobWrite_SyncBlockInfo();
        eRetVal = MEMIF_JOB_FAILED;

    }

    return eRetVal;
}

static MemIf_JobResultType Ea_JobWrite_RecordData( void )
{
    Std_ReturnType eStdRetVal = (Std_ReturnType)E_OK;
    MemIf_JobResultType eRetVal = MEMIF_JOB_FAILED;
    Ea_StateType *pEa_State = &Ea_State;
    struct ea_block_status *pblock_status =
            &block_status[pEa_State->Ea_uJobBlockIndex];

    eStdRetVal = Ea_Common_Write(pblock_status->block_data_addr,
                                 pEa_State->Ea_pJobWriteDataDestPtr, pblock_status->block_size);

    if (E_OK == eStdRetVal) {

        eRetVal = MEMIF_JOB_PENDING;
        pEa_State->Ea_eJob = EA_JOB_WRITE_RECORD_ACTIVE;
        pEa_State->Ea_eEepJob = EA_JOB_WRITE_RECORD_DATA;

    }
    else {

        Ea_JobWrite_SyncBlockInfo();
        eRetVal = MEMIF_JOB_FAILED;

    }

    return eRetVal;
}

static MemIf_JobResultType Ea_JobWrite_RecordActive( void )
{
    Std_ReturnType eStdRetVal = (Std_ReturnType)E_OK;
    MemIf_JobResultType eRetVal = MEMIF_JOB_FAILED;
    Ea_StateType *pEa_State = &Ea_State;
    struct ea_block_status *pblock_status =
            &block_status[pEa_State->Ea_uJobBlockIndex];
    struct ea_record_info *record_info = (struct ea_record_info *)(unsigned long int)ea_cache_buff;

    Mcal_MemSet(record_info, 0, sizeof(struct ea_record_info));
    record_info->record_status = EA_RECORD_VALID;
    record_info->record_num = pblock_status->block_number;
    record_info->record_size = pblock_status->block_size;
    record_info->record_address = pblock_status->block_data_addr;
    eStdRetVal = Ea_Common_Write(pblock_status->block_info_addr,
                                 (const uint8 *)record_info, sizeof(struct ea_record_info));

    if (E_OK == eStdRetVal) {

        eRetVal = MEMIF_JOB_PENDING;
        pblock_status->block_status = EA_RECORD_VALID;
        pEa_State->Ea_eJob = EA_JOB_DONE;
        pEa_State->Ea_eEepJob = EA_JOB_WRITE_RECORD_ACTIVE;

    }
    else {

        Ea_JobWrite_SyncBlockInfo();
        eRetVal = MEMIF_JOB_FAILED;

    }

    return eRetVal;
}

static MemIf_JobResultType Ea_Job_InvalBlock( void )
{
    MemIf_JobResultType eRetVal = MEMIF_JOB_FAILED;
    Ea_StateType *pEa_State = &Ea_State;
    struct ea_block_status *pblock_status =
            &block_status[pEa_State->Ea_uJobBlockIndex];

    Ea_JobWrite_BackupBlockInfo();

    switch (pblock_status->block_status) {
        case EA_RECORD_UNSET:
            EA_DEBUG("block in unset status, BlockIndex:%d BlockNumber:%d\n",
                     pEa_State->Ea_uJobBlockIndex, pEa_State->Ea_uJobBlockNumber);
            eRetVal = MEMIF_BLOCK_INCONSISTENT;
            break;

        case EA_BLOCK_INVALID:
            EA_DEBUG("block in invalid status, BlockIndex:%d BlockNumber:%d\n",
                     pEa_State->Ea_uJobBlockIndex, pEa_State->Ea_uJobBlockNumber);
            eRetVal = MEMIF_BLOCK_INVALID;
            break;

        case EA_RECORD_INVALID:
        case EA_RECORD_VALID:
            eRetVal = Ea_Job_InvalBlockInfo();
            break;

        default:
            EA_ERROR("block in unknown state, BlockIndex:%d BlockNumber:%d\n",
                     pEa_State->Ea_uJobBlockIndex, pEa_State->Ea_uJobBlockNumber);
            eRetVal = MEMIF_JOB_FAILED;
    }

    return eRetVal;
}

static MemIf_JobResultType Ea_Job_InvalBlockInfo( void )
{
    Std_ReturnType eStdRetVal = (Std_ReturnType)E_OK;
    MemIf_JobResultType eRetVal = MEMIF_JOB_FAILED;
    Ea_StateType *pEa_State = &Ea_State;
    struct ea_block_status *pblock_status =
            &block_status[pEa_State->Ea_uJobBlockIndex];
    struct ea_record_info *record_info = (struct ea_record_info *)(unsigned long int)ea_cache_buff;

    Mcal_MemSet(record_info, 0, sizeof(struct ea_record_info));
    record_info->record_status = EA_BLOCK_INVALID;
    record_info->record_num = pblock_status->block_number;
    record_info->record_size = pblock_status->block_size;
    record_info->record_address = pblock_status->block_data_addr;
    eStdRetVal = Ea_Common_Write(pblock_status->block_info_addr,
                                 (const uint8 *)record_info, sizeof(struct ea_record_info));

    if (E_OK == eStdRetVal) {

        eRetVal = MEMIF_JOB_PENDING;
        pblock_status->block_status = EA_BLOCK_INVALID;
        pEa_State->Ea_eJob = EA_JOB_DONE;
        pEa_State->Ea_eEepJob = EA_JOB_INVAL_BLOCK_INFO;

    }
    else {

        Ea_JobWrite_SyncBlockInfo();
        eRetVal = MEMIF_JOB_FAILED;

    }

    return eRetVal;
}

static MemIf_JobResultType Ea_Job_EraseImmediate( void )
{
    MemIf_JobResultType eRetVal = MEMIF_JOB_OK;

    return eRetVal;
}

static MemIf_JobResultType Ea_Job_Done( void )
{
    MemIf_JobResultType eRetVal = MEMIF_JOB_OK;

    return eRetVal;
}

#define EA_STOP_SEC_CODE
#include "Ea_MemMap.h"

#ifdef __cplusplus
}
#endif

/* End of file */
